package com.ufgov.smartclient.component.table;

import java.awt.Component;
import java.awt.Cursor;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.MouseEvent;
import java.util.Enumeration;

import javax.swing.JComponent;
import javax.swing.JTable;
import javax.swing.SwingUtilities;
import javax.swing.event.MouseInputListener;
import javax.swing.plaf.ComponentUI;
import javax.swing.plaf.basic.BasicTableHeaderUI;
import javax.swing.table.TableCellRenderer;
import javax.swing.table.TableColumn;
import javax.swing.table.TableColumnModel;

/**
 * 多表头TableHeaderUI
 */
public class GroupableTableHeaderUI extends BasicTableHeaderUI {

  protected class MouseHandler extends MouseInputHandler {

    @Override
    public void mouseClicked(MouseEvent e) {
      super.mouseClicked(e);
      if (tableHeader == null)
        return;
      if (SwingUtilities.isLeftMouseButton(e)) {
        if (tableHeader.getTable().getAutoResizeMode() != JTable.AUTO_RESIZE_OFF)
          return;
        if (tableHeader.getCursor() != resizeCursor)
          return;
        if (e.getClickCount() != 2)
          return;
        int resColumn = tableHeader.columnAtPoint(new Point(e.getPoint().x - 5, e
          .getPoint().y));
        if (resColumn == -1)
          return;
        tableHeader.fitColumnWidth(resColumn);
      } else if (SwingUtilities.isRightMouseButton(e) && e.getClickCount() == 1) {
        tableHeader.getTable().showPopupMenu(tableHeader, e.getX(), e.getY());
      }
    }

    @Override
    public void mouseReleased(MouseEvent e) {
      TableColumn draggedColumn = tableHeader.getDraggedColumn();
      TableColumn resizingColumn = tableHeader.getResizingColumn();
      super.mouseReleased(e);
      if (resizingColumn != null || draggedColumn != null) {
        tableHeader.getTable().savePreferences();
        //引发列宽改变
        if (resizingColumn != null) {
          ColumnResizeEvent event = new ColumnResizeEvent(tableHeader.getTable(),
            resizingColumn);
          tableHeader.getTable().fireColumnResized(event);
        }
      }
    }
  }

  private static Cursor resizeCursor = Cursor
    .getPredefinedCursor(Cursor.E_RESIZE_CURSOR);

  private JGroupableTableHeader tableHeader;

  /**
   * 表头高度
   */
  private int height;

  public static ComponentUI createUI(JComponent c) {
    return new GroupableTableHeaderUI();
  }

  /**
   * 返回表头的尺寸
   * @param width long - 表头总宽度
   * @return Dimension
   */
  private Dimension createHeaderSize(long width) {
    TableColumnModel columnModel = tableHeader.getColumnModel();

    //计算出Margin宽度
    int columnMarginWidth = columnModel.getColumnMargin()
      * columnModel.getColumnCount();

    //加上Margin
    width += columnMarginWidth;

    //查检是否超出Integer范围
    if (width > Integer.MAX_VALUE) {
      width = Integer.MAX_VALUE;
    }
    //return new Dimension((int)width, 100);
    return new Dimension((int) width, getHeaderHeight());
  }

  /**
   * 计算表头高度
   * @return int
   */
  public int getHeaderHeight() {
    int height = 0;
    TableColumnModel columnModel = tableHeader.getColumnModel();

    //循环所有列
    for (int column = 0; column < columnModel.getColumnCount(); column++) {
      //取出列
      TableColumn tableColumn = columnModel.getColumn(column);
      //渲染器
      TableCellRenderer renderer = tableColumn.getHeaderRenderer();
      if (renderer == null) {
        renderer = tableHeader.getDefaultRenderer();
      }
      Component comp = renderer.getTableCellRendererComponent(
        tableHeader.getTable(), tableColumn.getHeaderValue(), false, false, -1,
        column);
      //取高度
      int cHeight = comp.getPreferredSize().height;

      //如果存在表头，表头高度加倍，以保证显示正常
      if ((tableHeader).columnGroups.size() > 0)
        cHeight *= 2;

      //设置表头高度
      height = Math.max(height, cHeight);
    }
    height = Math.max(height, this.height);
    return height;
  }

  /**
   * getPreferredSize，覆盖BasicTableHeaderUI.getPreferredSize，返回改动过的尺寸
   * @param c JComponent
   * @return Dimension
   */
  @Override
  public Dimension getPreferredSize(JComponent c) {
    long width = 0;
    Enumeration enumeration = tableHeader.getColumnModel().getColumns();
    while (enumeration.hasMoreElements()) {
      TableColumn aColumn = (TableColumn) enumeration.nextElement();
      width = width + aColumn.getWidth();
    }
    return createHeaderSize(width);
  }

  @Override
  public void paint(Graphics g, JComponent c) {
    if (tableHeader.getColumnModel().getColumnCount() <= 0) {
      return;
    }
    boolean ltr = tableHeader.getComponentOrientation().isLeftToRight();

    Rectangle clip = g.getClipBounds();
    Point left = clip.getLocation();
    Point right = new Point(clip.x + clip.width - 1, clip.y);
    TableColumnModel cm = tableHeader.getColumnModel();
    int cMin = tableHeader.columnAtPoint(ltr ? left : right);
    int cMax = tableHeader.columnAtPoint(ltr ? right : left);
    // This should never happen. 
    if (cMin == -1) {
      cMin = 0;
    }
    // If the table does not have enough columns to fill the view we'll get -1.
    // Replace this with the index of the last column.
    if (cMax == -1) {
      cMax = cm.getColumnCount() - 1;
    }

    TableColumn draggedColumn = tableHeader.getDraggedColumn();
    TableColumn aColumn;
    if (ltr) {
      synchronized (cm) {
        for (int column = cMax; column >= cMin; column--) {
          aColumn = cm.getColumn(column);
          Rectangle cellRect = tableHeader.getHeaderRect(column);
          if (aColumn != draggedColumn) {
            paintCell(g, cellRect, column);
          }
        }
      }

    } else {
      synchronized (cm) {
        for (int column = cMax; column >= cMin; column--) {
          aColumn = cm.getColumn(column);
          Rectangle cellRect = tableHeader.getHeaderRect(column);
          if (aColumn != draggedColumn) {
            paintCell(g, cellRect, column);
          }
        }
      }
    }

    // Paint the dragged column if we are dragging. 
    if (draggedColumn != null) {
      int draggedColumnIndex = viewIndexForColumn(draggedColumn);
      Rectangle draggedCellRect = tableHeader.getHeaderRect(draggedColumnIndex);

      // Draw a gray well in place of the moving column. 
      g.setColor(tableHeader.getParent().getBackground());
      g.fillRect(draggedCellRect.x, draggedCellRect.y, draggedCellRect.width,
        draggedCellRect.height);

      draggedCellRect.x += tableHeader.getDraggedDistance();

      // Fill the background. 
      g.setColor(tableHeader.getBackground());
      g.fillRect(draggedCellRect.x, draggedCellRect.y, draggedCellRect.width,
        draggedCellRect.height);

      paintCell(g, draggedCellRect, draggedColumnIndex);
    }

    paintGroupHeader((Graphics2D) g);
    rendererPane.removeAll();
  }

  protected void paintGroupHeader(Graphics2D g) {
    ColumnGroup[] columnGroups = tableHeader.getColumnGroups();
    for (int index = columnGroups.length - 1; index >= 0; index--) {
      paintColumnGroup(g, columnGroups[index]);
    }
    //    for (int index = 0; index < columnGroups.length; index++) {
    //      paintColumnGroup(g, columnGroups[index]);
    //    }
  }

  protected void paintColumnGroup(Graphics2D g, ColumnGroup group) {
    Component comp = group.getHeaderRenderer().getTableCellRendererComponent(
      tableHeader.getTable(), group.getHeaderValue(), false, false, 0, 0);

    for (Rectangle rect : group.getHeadRects().keySet()) {
      g.fill(rect);
      rendererPane.paintComponent(g, comp, tableHeader, rect);
    }
  }

  private Component getHeaderRenderer(int columnIndex) {
    TableColumn aColumn = tableHeader.getColumnModel().getColumn(columnIndex);
    TableCellRenderer renderer = aColumn.getHeaderRenderer();
    if (renderer == null) {
      renderer = tableHeader.getDefaultRenderer();
    }

    boolean hasFocus = false;
    return renderer.getTableCellRendererComponent(tableHeader.getTable(), aColumn
      .getHeaderValue(), false, hasFocus, -1, columnIndex);
  }

  protected void paintCell(Graphics g, Rectangle cellRect, int columnIndex) {
    if (cellRect.width < 1 || cellRect.height < 1)
      return;
    g.fillRect(cellRect.x, cellRect.y, cellRect.width, cellRect.height);
    Component component = getHeaderRenderer(columnIndex);
    rendererPane.paintComponent(g, component, tableHeader, cellRect.x, cellRect.y,
      cellRect.width, cellRect.height, true);
  }

  private int viewIndexForColumn(TableColumn aColumn) {
    TableColumnModel cm = tableHeader.getColumnModel();
    for (int column = 0; column < cm.getColumnCount(); column++) {
      if (cm.getColumn(column) == aColumn) {
        return column;
      }
    }
    return -1;
  }

  @Override
  public void installUI(JComponent c) {
    super.installUI(c);
    tableHeader = (JGroupableTableHeader) c;
  }

  @Override
  protected MouseInputListener createMouseInputListener() {
    return new MouseHandler();
  }

  @Override
  public void uninstallUI(JComponent c) {
    super.uninstallUI(c);
  }

  @Override
  public int getRolloverColumn() {
    return super.getRolloverColumn();
  }

  @Override
  protected void rolloverColumnUpdated(int oldColumn, int newColumn) {
    super.rolloverColumnUpdated(oldColumn, newColumn);
    if (newColumn == -1)
      return;
    this.header.repaint();
  }

}
